#include "StdAfx.h"
#include "Sphere.h"


CSphere::CSphere(void)
: m_fRadius(0.f)
{
}


CSphere::~CSphere(void)
{
}

void CSphere::Init(const CVector3D& vPosition, DATA_TYPE fRadius, 
				   const CColor4& vColor, const CMaterial& material)
{
	SetPosition(vPosition);
	m_fRadius = fRadius;
	m_vColor = vColor;
	m_material = material;
}

bool CSphere::IsIntersect(const CRay& vRay, DATA_TYPE& t, bool& bInside, CVector3D& vNormal) const
{
	CVector3D l = GetPosition() - vRay.GetOrigin();
	DATA_TYPE s = l.Dot(vRay.GetDir());
	DATA_TYPE lSquare = l.Dot(l);
	DATA_TYPE radiusSquare = m_fRadius * m_fRadius;
	if (s < 0.f && lSquare > radiusSquare)
	{
		return false;
	}
	DATA_TYPE mSquare = lSquare - s * s;
	if (mSquare > radiusSquare)
	{
		return false;
	}
	DATA_TYPE q = sqrt(radiusSquare - mSquare);
	
	if (lSquare > radiusSquare)
	{
		bInside = false;
		t = s - q;
	}
	else
	{
		bInside = true;
		t = s + q;
	}
	vNormal = GetNormal(vRay.GetOrigin() + t * vRay.GetDir());

	return true;
}

CVector3D CSphere::GetNormal(const CVector3D& vPoint) const
{
	return (vPoint - GetPosition()).Normalize();
}

bool CSphere::IsInGeometry(const CVector3D& vPoint) const
{
	return (vPoint - GetPosition()).GetSquareLength() < m_fRadius * m_fRadius;
}

bool CSphere::GetAllIntersectionPoints(const CRay& vRay, vector<IntersectionPoint>& vIntersectionPoints) const
{
	CVector3D l = GetPosition() - vRay.GetOrigin();
	DATA_TYPE s = l.Dot(vRay.GetDir());
	DATA_TYPE lSquare = l.Dot(l);
	DATA_TYPE radiusSquare = m_fRadius * m_fRadius;
	if (s < 0.f && lSquare > radiusSquare)
	{
		return false;
	}
	DATA_TYPE mSquare = lSquare - s * s;
	if (mSquare > radiusSquare)
	{
		return false;
	}
	DATA_TYPE q = sqrt(radiusSquare - mSquare);

	if (lSquare > radiusSquare)
	{
		vIntersectionPoints.push_back(IntersectionPoint(s - q, false, GetNormal(vRay.GetOrigin() + (s - q) * vRay.GetDir())));
		vIntersectionPoints.push_back(IntersectionPoint(s + q, true,  GetNormal(vRay.GetOrigin() + (s + q) * vRay.GetDir())));
	}
	else
	{
		vIntersectionPoints.push_back(IntersectionPoint(s + q, true,  GetNormal(vRay.GetOrigin() + (s + q) * vRay.GetDir())));
	}

	return true;
}

DATA_TYPE CSphere::GetMaxValue(int iAxis) const
{
	return GetPosition()[iAxis] + m_fRadius;
}

DATA_TYPE CSphere::GetMinValue(int iAxis) const
{
	return GetPosition()[iAxis] - m_fRadius;
}